package com.sky.aspect;

import com.sky.annotation.AutoFill;
import com.sky.constant.AutoFillConstant;
import com.sky.context.BaseContext;
import com.sky.enumeration.OperationType;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.Signature;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.stereotype.Component;

import java.lang.reflect.Method;
import java.time.LocalDateTime;

@Component
@Aspect
@Slf4j
public class AutoFillAspect {

    @Before("execution(* com.sky.mapper.*.*(..)) && @annotation(com.sky.annotation.AutoFill)") //扫描mapper包和@autofill
    public void before(JoinPoint joinPoint) throws Exception {
        log.info("开始公共字段填充");

//    1.获取原始方法上的注解 AutoFill 对象, 目的是区分insert 和 update 操作
//        1.1获取原始方法签名对象 (aop 提供的签名对象)
        MethodSignature methodSignature = (MethodSignature) joinPoint.getSignature();
//        1.2获取方法上的注解
        AutoFill autoFill = methodSignature.getMethod().getAnnotation(AutoFill.class);
//        1.3获取里面操作类型对象
        OperationType operationType = autoFill.value();
//    2.获取原始方法参数对象Employee
        Object[] objects = joinPoint.getArgs();
//        安全操作不能为空
        if (objects == null || objects.length == 0) {
            log.info("当前方法没有合适的参数填充公告字段");
        }
//        获取第一个参数对象
        Object object = objects[0];
        Class<?> aClass = object.getClass();
//    3.对参数对象进行填充
//        3.0 获取填充数据
        Long empId = BaseContext.getCurrentId();
        LocalDateTime now = LocalDateTime.now();
//        3.1 填充修改人和修改时间
//        使用反射获取object公共字段的set方法,aClass.getMethod(方法名，方法参数字节码对象.....)
        Method setUpdateUserMethod = aClass.getMethod(AutoFillConstant.SET_UPDATE_USER, Long.class);//修改人的set方法
        Method setUpdateTimeMethod = aClass.getMethod(AutoFillConstant.SET_UPDATE_TIME, LocalDateTime.class);//修改时间的set方法
//        反射执行方法填充数据
        setUpdateUserMethod.invoke(object,empId);
        setUpdateTimeMethod.invoke(object,now);
//        3.2 如果 insert 操作, 再填充创建人和创建时间
        if (operationType == OperationType.INSERT){
            Method setCreateUserMethod = aClass.getMethod(AutoFillConstant.SET_CREATE_USER, Long.class);//创建人的set方法
            Method setCreateTimeMethod = aClass.getMethod(AutoFillConstant.SET_CREATE_TIME, LocalDateTime.class);//创建时间的set方法
            setCreateUserMethod.invoke(object, empId);
            setCreateTimeMethod.invoke(object, now);
        }
    }
}
